package com.le.tester.imooc.oldfairy.concurrent;

import java.util.concurrent.*;

/**
 * createTime：2023/6/16 14:00
 * description：队列控制并发，一个线程控制队列，五个线程对应五个哲学家
 */
public class DiningPhilosophersBlockingQueue implements Runnable {

    Philosopher[] phis;
    volatile int forks[];
    LinkedBlockingQueue<Philosopher> workingQueue;
    LinkedBlockingQueue<Philosopher> managerQueue;
    DelayQueue<DelayInterruptingThread> delayQueue = new DelayQueue<>();

    @Override
    public void run() {
        ExecutorService service = Executors.newFixedThreadPool(7);
        for (int i = 0; i < 5; i++) {
            service.submit(new Worker());
        }
        service.submit(new ContentionManager());
        service.submit(new InterruptingWorker());
    }
    //DelayQueue<DelayInterruptingThread> delayQueue = new DelayQueue<>();


    //竞争管理
    class ContentionManager implements Runnable {

        @Override
        public void run() {
            while (true) {
                //哲学家
                try {
                    //一个线程来控制的队列，可以不考虑吧并发情况
                    Philosopher phi = managerQueue.take();
                    if (phi.checkLeft(forks) && phi.checkRight(forks)) {
                        phi.takeLeft(forks);
                        phi.takeRight(forks);
                        //eating
                        workingQueue.offer(phi);
                    } else {
                        managerQueue.offer(phi);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    //对于workingQueue.offer,则是eating,else managerQueue,则是thinking
    class Worker implements Runnable {

        @Override
        public void run() {

            while (true) {
                Philosopher phi = null;
                try {
                    phi = workingQueue.take();
                    //workingQueue在处理io
                    if (phi.getState().equalsIgnoreCase("Hungry")) {
                        DelayInterruptingThread delayQueueThread = new DelayInterruptingThread(Thread.currentThread(), 1000);
                        delayQueue.offer(delayQueueThread);
                        //eating
                        phi.eating();
                        //eating success
                        delayQueueThread.commit();
                        phi.putLeft(forks);
                        phi.putRight(forks);
                        phi.finished();
                        workingQueue.offer(phi);
                    } else {
                        phi.thinking();
                        //managerQueue是在处理竞争
                        managerQueue.offer(phi);
                    }
                } catch (InterruptedException e) {
                    //发生中断的时候
                    if (phi != null) {
                        phi.putLeft(forks);
                        phi.putRight(forks);
                        if (phi.getState().equalsIgnoreCase("Eating")) {
                            phi.setState("Hungry");
                        }
                        managerQueue.offer(phi);
                    }
                }
            }
        }
    }

    //定时器不如延迟队列的实现
    class DelayInterruptingThread implements Delayed {

        long time;
        Thread current;

        public DelayInterruptingThread(Thread t, long delay) {
            this.time = delay;
            this.current = t;
        }

        @Override
        public long getDelay(TimeUnit unit) {
            return time - System.currentTimeMillis();
        }

        @Override
        public int compareTo(Delayed o) {
            return (int) (time - ((DelayInterruptingThread) o).time);
        }

        public void rollback() {
            if (this.current != null) {
                //线程中断
                this.current.interrupt();
            }
        }

        //线程置空
        public void commit() {
            this.current = null;
        }
    }

    //中断的eating
    class InterruptingWorker implements Runnable {

        @Override
        public void run() {
            while (true) {
                try {
                    DelayInterruptingThread delayInterruptingThread = delayQueue.take();
                    delayInterruptingThread.rollback();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        new DiningPhilosophersBlockingQueue().run();

    }


}
